package com.starsoft.trade.web;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.starsoft.frame.base.bean.BaseAcount;
import com.starsoft.frame.base.service.UserService;
import com.starsoft.frame.core.web.WebUtil;
import com.starsoft.frame.util.DateUtil;
import com.starsoft.frame.util.StringUtil;
import com.starsoft.smdc.bean.SmdcMarketDaily;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.service.HolidayService;
import com.starsoft.smdc.service.MarketDailyService;
import com.starsoft.smdc.service.SecurityService;
import com.starsoft.trade.bean.TradeAcount;
import com.starsoft.trade.bean.TradeAcountStatus;
import com.starsoft.trade.bean.TradeBill;
import com.starsoft.trade.bean.TradeSummary;
import com.starsoft.trade.service.AcountStatusService;
import com.starsoft.trade.service.TradeAcountService;
import com.starsoft.trade.service.TradeBillService;
import com.starsoft.trade.service.TradeSummaryService;

@RestController
@RequestMapping(value = "/trade/report")
public class AcountGatherController {

	@Autowired
	private AcountStatusService acountStatusService;
	@Autowired
	private TradeAcountService tradeAcountService;
	@Autowired
	private HolidayService holidayService;
	@Autowired
	private TradeBillService tradeBillService;
	@Autowired
	private TradeSummaryService tradeSummaryService;
	@Autowired
	private MarketDailyService marketDailyService;
	@Autowired
	private SecurityService securityService;
	
	@RequestMapping(value="/getRealAcounts")
	public List<BaseAcount> getRealAcounts(HttpServletRequest request){
		Integer userId = UserService.getUserContext().getUserId();
		return tradeAcountService.getRealAcountByUser(userId);
	}
	
	@RequestMapping(value="/gather")
	public Map<String, Object> gather(HttpServletRequest request){
		if("true".equalsIgnoreCase(request.getParameter("forceRefresh"))){
			List<TradeAcount> acounts = getRealAcount(request, new Date());
			for (TradeAcount acount : acounts) {
				Integer acountId = acount.getAcountId();
				Date initDate = tradeAcountService.get(acountId).getInitDate();
				acountStatusService.updateStatus(acountId, initDate, null);
			}
		}
		
		Map<String, Object> model = new HashMap<>();
		model.putAll(gatherStatus(request));
		model.putAll(gatherChart(request));
		return model;
	}

	private Map<String, Object> gatherChart(HttpServletRequest request) {
		List<TradeAcount> acounts = getRealAcount(request , new Date());
		
		TreeMap<Date, TradeSummary> combinedSummaryMap = new TreeMap<>();
		Date beginDate = null;
		
		for (TradeAcount tradeAcount : acounts) {
			Integer acountId = tradeAcount.getAcountId();
			Date accBeginDate = getBeginDate(request, acountId);
			if(beginDate==null || beginDate.after(accBeginDate)){
				beginDate = accBeginDate;
			}
			Date adjBeginDate = holidayService.getNextBusinessDay(accBeginDate, -1);
			List<TradeSummary> summaryList = tradeSummaryService.getAcountBetween(acountId, adjBeginDate, null);
			for (TradeSummary summary : summaryList) {
				Date date = summary.getId().getAsofdate();
				if (combinedSummaryMap.containsKey(date)) {
					TradeSummary tradeSummaryA = combinedSummaryMap.get(date);
					TradeSummary combinedSummary = tradeSummaryService.combine(tradeSummaryA, summary);
					combinedSummaryMap.put(date, combinedSummary);
				} else {
					combinedSummaryMap.put(date, summary);
				}
			}
		}
		
		TradeSummary summaryBase = combinedSummaryMap.firstEntry().getValue();		
		String indexSecId = "000300.ss";
		SmdcSecurity indexSec = securityService.get(indexSecId);
		Map<String, SmdcMarketDaily> indexMarkets = new HashMap<>();
		List<SmdcMarketDaily> indexMarketList = marketDailyService.getBetweenAnd(indexSecId,
				summaryBase.getId().getAsofdate(), new Date());
		indexMarketList.forEach(market -> {
			String dateStr = DateUtil.toString(market.getId().getTradeDate());
			indexMarkets.put(dateStr, market);
		});
		Date lastDate = combinedSummaryMap.lastKey();
		if(!indexMarkets.containsKey(DateUtil.toString(lastDate))){
			SmdcMarketDaily lastDateMarket = marketDailyService.getMarketDailyOnTime(indexSecId, lastDate);
			indexMarkets.put(DateUtil.toString(lastDate), lastDateMarket);
		}
		
		SmdcMarketDaily indexBaseMarket = indexMarkets.get(DateUtil.toString(summaryBase.getId().getAsofdate()));
		
		List<Date> timeLine = new ArrayList<>();
		List<Double> baseProfit = new ArrayList<>();
		List<Double> profit = new ArrayList<>();
		List<Double> asset = new ArrayList<>();
		List<Double> profitMoney = new ArrayList<>();
		List<Double> marketValue = new ArrayList<>();
		double profitValue = 1/(1+summaryBase.getProfitDay());
		for (TradeSummary summary : combinedSummaryMap.values()) {
			Date asof = summary.getId().getAsofdate();
			timeLine.add(asof);
			SmdcMarketDaily indexMarket = indexMarkets.get(DateUtil.toString(asof));
			baseProfit.add(indexMarket.getClosePrice()/indexBaseMarket.getClosePrice()*100-100);
			profitValue = profitValue*(1+summary.getProfitDay());
			profit.add(profitValue * 100-100);
			asset.add(summary.getNetAssert());
			profitMoney.add(summary.getProfitMoney()-summaryBase.getProfitMoney());
			marketValue.add(summary.getMarketValue());
		}
		Map<String, Object> chartResult = new HashMap<>();
		chartResult.put("timeLine", timeLine);
		chartResult.put("baseProfit", baseProfit);
		chartResult.put("profit", profit);
		chartResult.put("asset", asset);
		chartResult.put("profitMoney", profitMoney);
		chartResult.put("marketValue", marketValue);
		chartResult.put("baseIndexName", indexSec.getSecName());
		Map<String, Object> requestData = new HashMap<String, Object>();
		requestData.put("beginDateType", request.getParameter("beginDateType"));
		requestData.put("beginDate", beginDate);
		chartResult.put("requestData", requestData);
		Map<String, Object> model = new HashMap<>();
		model.put("chart", chartResult);
		return model;
	}

	@RequestMapping(value="/gatherstatus")
	public Map<String, Object> gatherStatus(HttpServletRequest request) {
		TradeAcountStatus gatherStatus = null;
		List<TradeBill> gatherLillList = new ArrayList<TradeBill>();
		Date summaryDate = getSummaryDate(request);
		
		List<TradeAcount> acounts = getRealAcount(request, summaryDate);
		for (TradeAcount acount : acounts) {
			if (!tradeAcountService.isAlive(acount, summaryDate)) {
				continue;
			}
			Integer acountId = acount.getAcountId();
			TradeAcountStatus status = null;
			if(DateUtil.isToday(summaryDate)){
				status = acountStatusService.updateStatus(acountId, new Date(), null);
			} else {
				status = acountStatusService.updateAndGet(acountId, summaryDate);
			}
			List<TradeBill> billList = tradeBillService.getBills(acountId, status.getAsofDate());

			if(gatherStatus == null){
				gatherStatus = status;
			} else {
				gatherStatus = acountStatusService.combine(gatherStatus, status);
			}
			gatherLillList.addAll(billList);
		}
		
		Map<String, Object> statusMap = acountStatusService.convertBean(gatherStatus);
		statusMap.put("bills", tradeBillService.convertToMap(gatherLillList));
		
		Map<String, Object> model = new HashMap<>();
		model.put("status", statusMap);
		return model;
	}

	private List<TradeAcount> getRealAcount(HttpServletRequest request, Date summaryDate){
		Integer userId = UserService.getUserContext().getUserId();
		String acountIdStr = request.getParameter("acounts");

		List<Integer> acountIds = new ArrayList<>();
		List<TradeAcount> acountBeans = new ArrayList<>();
		if (StringUtil.isEmpty(acountIdStr) || "all".equalsIgnoreCase(acountIdStr)) {
			List<BaseAcount> baseAcounts = tradeAcountService.getRealAcountByUser(userId);
			baseAcounts.forEach(baseAcount->acountIds.add(baseAcount.getAcountId()));
		} else {
			for(String acountId : acountIdStr.trim().split(",")){
				acountIds.add(Integer.parseInt(acountId.trim()));
			}
		}
		for(Integer acountId : acountIds){
			acountBeans.add(tradeAcountService.get(acountId));
		}
		return acountBeans;
	}
	
	private Date getSummaryDate(HttpServletRequest request){
		Date summaryDate = WebUtil.getDate(request, "summaryDate", "yyyy-MM-dd");
		String summaryDateType = request.getParameter("summaryDateType");
		if(summaryDate==null){
			summaryDate = new Date();
		}
		if("lastDay".equalsIgnoreCase(summaryDateType)){
			summaryDate = holidayService.getNextBusinessDay(summaryDate, -1);
		} else if("nextDay".equalsIgnoreCase(summaryDateType)){
			summaryDate = holidayService.getNextBusinessDay(summaryDate, 1);
		}
		if(summaryDate.after(new Date())){
			summaryDate = new Date();
		}

		boolean isBusy = holidayService.isBusinessDay(summaryDate);
		if (DateUtil.isToday(summaryDate)){
			boolean isBeforeOpen = holidayService.isBeforeOpen(new Date());
			if(!isBusy || isBeforeOpen) {
				summaryDate = holidayService.getNextBusinessDay(summaryDate, -1);
			}
		} else if(!isBusy){
			summaryDate = holidayService.getNextBusinessDay(summaryDate, -1);
		}
		return DateUtil.floorTime(summaryDate);
	}
	
	private Date getBeginDate(HttpServletRequest request, Integer acountId) {
		ZonedDateTime now = ZonedDateTime.now();
		String beginDateType = request.getParameter("beginDateType");
		Date beginDate = WebUtil.getDate(request, "beginDate", "yyyy-MM-dd");
		if (!StringUtil.isEmpty(beginDateType)) {
			if ("thisMonth".equalsIgnoreCase(beginDateType)) {
				beginDate = Date.from(now.withDayOfMonth(1).toInstant());
			} else if ("threeMonth".equalsIgnoreCase(beginDateType)) {
				beginDate =  Date.from(now.withDayOfMonth(1).plusMonths(-2).toInstant());
			} else if ("thisYear".equalsIgnoreCase(beginDateType)) {
				beginDate =  Date.from(now.withDayOfYear(1).toInstant());
			} else if ("all".equalsIgnoreCase(beginDateType)) {
				beginDate = null;
			} else if (StringUtil.isEmpty(beginDate)) {
				beginDate = null;
			}
		} else if (beginDate == null) {
			beginDate = Date.from(now.withDayOfYear(1).toInstant());
		}
		Date initDate = tradeAcountService.get(acountId).getInitDate();
		if ((beginDate != null && beginDate.before(initDate)) || beginDate == null) {
			beginDate = initDate;
		}
		beginDate = holidayService.getBusinessDay(beginDate, false);
		Date nowDate = new Date();
		if(beginDate.after(nowDate) && !DateUtil.isSameDay(beginDate, nowDate)){
			beginDate = holidayService.getNextBusinessDay(nowDate, -1);
		}
		return beginDate;
	}
}
